<template>
  <div class="app-container">
    <h1>Vue 懒加载示例教学</h1>

    <section class="example-section">
      <h2>1. 组件懒加载</h2>
      <p>组件懒加载可以优化初始加载时间，只在需要时才加载组件</p>
      <div class="demo-box">
        <button @click="showLazyComponent = !showLazyComponent">
          {{ showLazyComponent ? '隐藏组件' : '加载组件' }}
        </button>
        <component v-if="showLazyComponent" :is="lazyComponent" />
      </div>
      <div class="code-preview">
        <pre><code>// 懒加载组件示例
const LazyComponent = () => import('./components/LazyComponent.vue')</code></pre>
      </div>
    </section>

    <section class="example-section">
      <h2>2. 图片懒加载</h2>
      <p>图片只有当滚动到可视区域时才会被加载</p>
      <div class="demo-box image-container">
        <div v-for="(img, index) in images" :key="index" class="lazy-image-wrapper">
          <img
              :src="img.loaded ? img.url : ''"
              :alt="img.alt"
              :class="['lazy-image', img.loaded ? 'loaded' : '']"
          />
          <div class="image-placeholder" v-if="!img.loaded">加载中...</div>
        </div>
      </div>
      <div class="code-preview">
        <pre><code>// 使用Intersection Observer实现图片懒加载
setupLazyImageLoading() {
  this.images.forEach((image, index) => {
    const observer = new IntersectionObserver((entries) => {
      if (entries[0].isIntersecting) {
        const img = new Image();
        img.src = image.url;
        img.onload = () => {
          this.images[index].loaded = true;
        };
        observer.disconnect();
      }
    });
    observer.observe(imgContainers[index]);
  });
}</code></pre>
      </div>
    </section>

    <section class="example-section">
      <h2>3. 列表数据懒加载</h2>
      <p>滚动到底部时自动加载更多数据</p>
      <div class="demo-box list-container" ref="listContainer">
        <ul class="lazy-list">
          <li v-for="(item, index) in displayedItems" :key="index" class="list-item">
            {{ item }}
          </li>
        </ul>
        <div v-if="loading" class="loading">加载中...</div>
      </div>
      <div class="code-preview">
        <pre><code>// 监听滚动事件加载更多数据
mounted() {
  const observer = new IntersectionObserver((entries) => {
    if (entries[0].isIntersecting && !this.loading) {
      this.loadMore();
    }
  });
  observer.observe(this.$refs.loadingTrigger);
}</code></pre>
      </div>
    </section>
  </div>
</template>

<script>
// 懒加载组件
const LazyComponent = () => import('./components/LazyComponent.vue');

export default {
  name: 'App',
  data() {
    return {
      showLazyComponent: false,
      lazyComponent: LazyComponent,
      images: [
        { url: 'https://picsum.photos/id/1/400/300', alt: '图片1', loaded: false },
        { url: 'https://picsum.photos/id/2/400/300', alt: '图片2', loaded: false },
        { url: 'https://picsum.photos/id/3/400/300', alt: '图片3', loaded: false },
        { url: 'https://picsum.photos/id/4/400/300', alt: '图片4', loaded: false },
        { url: 'https://picsum.photos/id/5/400/300', alt: '图片5', loaded: false },
        { url: 'https://picsum.photos/id/6/400/300', alt: '图片6', loaded: false },
      ],
      allItems: Array.from({ length: 100 }, (_, i) => `列表项 ${i + 1}`),
      displayedItems: [],
      loading: false,
      page: 0,
      pageSize: 10
    };
  },
  mounted() {
    this.loadMore();

    // 注册图片懒加载
    this.setupLazyImageLoading();

    // 设置滚动加载
    this.setupInfiniteScroll();
  },
  methods: {
    loadMore() {
      this.loading = true;

      // 模拟网络请求延迟
      setTimeout(() => {
        const start = this.page * this.pageSize;
        const end = start + this.pageSize;
        const newItems = this.allItems.slice(start, end);
        this.displayedItems = [...this.displayedItems, ...newItems];
        this.page++;
        this.loading = false;
      }, 800);
    },
    setupLazyImageLoading() {
      // 为每张图片创建一个观察器
      this.$nextTick(() => {
        const imgContainers = document.querySelectorAll('.lazy-image-wrapper');

        this.images.forEach((image, index) => {
          const observer = new IntersectionObserver((entries) => {
            if (entries[0].isIntersecting) {
              const img = new Image();
              img.src = image.url;
              img.onload = () => {
                this.images[index].loaded = true;
              };
              observer.disconnect();
            }
          });

          // 观察容器元素
          if (imgContainers[index]) {
            observer.observe(imgContainers[index]);
          }
        });
      });
    },
    setupInfiniteScroll() {
      // 创建监听滚动到底部的观察器
      const observer = new IntersectionObserver((entries) => {
        if (entries[0].isIntersecting && !this.loading) {
          this.loadMore();
        }
      });

      this.$nextTick(() => {
        // 创建一个触发加载的元素
        const loadingTrigger = document.createElement('div');
        loadingTrigger.className = 'loading-trigger';
        this.$refs.listContainer.appendChild(loadingTrigger);
        observer.observe(loadingTrigger);
      });
    }
  }
};
</script>

<style>
.app-container {
  font-family: Arial, sans-serif;
  max-width: 800px;
  margin: 0 auto;
  padding: 20px;
}

h1 {
  color: #2c3e50;
  border-bottom: 2px solid #42b983;
  padding-bottom: 10px;
}

.example-section {
  margin-bottom: 40px;
  border: 1px solid #e0e0e0;
  border-radius: 8px;
  padding: 20px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.05);
}

h2 {
  color: #42b983;
  margin-top: 0;
}

.demo-box {
  background-color: #f8f8f8;
  border-radius: 6px;
  padding: 20px;
  margin: 15px 0;
  min-height: 100px;
}

.code-preview {
  background-color: #2c3e50;
  border-radius: 6px;
  padding: 15px;
  overflow-x: auto;
}

.code-preview pre {
  margin: 0;
}

.code-preview code {
  color: #f8f8f8;
  font-family: monospace;
  font-size: 14px;
}

button {
  background-color: #42b983;
  color: white;
  border: none;
  padding: 8px 16px;
  border-radius: 4px;
  cursor: pointer;
  transition: background-color 0.3s;
}

button:hover {
  background-color: #3aa876;
}

.image-container {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 15px;
}

.lazy-image-wrapper {
  position: relative;
  height: 150px;
  background-color: #e0e0e0;
  border-radius: 4px;
  overflow: hidden;
}

.image-placeholder {
  display: flex;
  justify-content: center;
  align-items: center;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  color: #666;
}

.lazy-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 0.5s;
}

.lazy-image.loaded {
  opacity: 1;
}

.list-container {
  height: 300px;
  overflow-y: auto;
  position: relative;
}

.lazy-list {
  padding: 0;
  margin: 0;
  list-style-type: none;
}

.list-item {
  padding: 12px 16px;
  border-bottom: 1px solid #e0e0e0;
}

.loading {
  text-align: center;
  padding: 10px;
  color: #666;
}

.loading-trigger {
  height: 10px;
  width: 100%;
}
</style>